#include "pch.h"
#include "VersionControl.h"
#include "Utility.h"

static std::string EnsureQuoted(const std::string& path)
{
    if (path.empty()) return std::string();
    if (!path.empty() && path.front() == '"' && path.back() == '"') return path;
    return std::string("\"") + path + "\"";
}

// ---------------- TortoiseSVN ----------------
TortoiseSvnClient::TortoiseSvnClient(std::string tortoiseProcPath)
{
    if (tortoiseProcPath.empty()) m_exe = "TortoiseProc.exe";
    else m_exe = EnsureQuoted(tortoiseProcPath);
}

void TortoiseSvnClient::RunCommand(const std::string& command, const std::string& path)
{
    const std::string full = m_exe + " /command:" + command + " /path:" + EnsureQuoted(path);
    Utility::StartProcessAsync(full);
}

void TortoiseSvnClient::Update(const std::string& workingCopyPath)
{ RunCommand("update", workingCopyPath); }

void TortoiseSvnClient::Commit(const std::string& workingCopyPath)
{ RunCommand("commit", workingCopyPath); }

void TortoiseSvnClient::Log(const std::string& workingCopyPath)
{ RunCommand("log", workingCopyPath); }

void TortoiseSvnClient::Revert(const std::string& workingCopyPath)
{ RunCommand("revert", workingCopyPath); }

void TortoiseSvnClient::Cleanup(const std::string& workingCopyPath)
{ RunCommand("cleanup", workingCopyPath); }

void TortoiseSvnClient::Merge(const std::string& source, const std::string& targetWorkingCopyPath)
{
    const std::string full = m_exe + " /command:merge /path:" + EnsureQuoted(targetWorkingCopyPath) + " /fromurl:" + EnsureQuoted(source);
    Utility::StartProcessAsync(full);
}

// ---------------- TortoiseGit ----------------
TortoiseGitClient::TortoiseGitClient(std::string tortoiseGitProcPath)
{
    if (tortoiseGitProcPath.empty()) m_exe = "TortoiseGitProc.exe";
    else m_exe = EnsureQuoted(tortoiseGitProcPath);
}

void TortoiseGitClient::RunCommand(const std::string& command, const std::string& path)
{
    const std::string full = m_exe + " /command:" + command + " /path:" + EnsureQuoted(path);
    Utility::StartProcessAsync(full);
}

void TortoiseGitClient::Update(const std::string& workingCopyPath)
{ RunCommand("pull", workingCopyPath); }

void TortoiseGitClient::Commit(const std::string& workingCopyPath)
{ RunCommand("commit", workingCopyPath); }

void TortoiseGitClient::Log(const std::string& workingCopyPath)
{ RunCommand("log", workingCopyPath); }

void TortoiseGitClient::Revert(const std::string& workingCopyPath)
{ RunCommand("revert", workingCopyPath); }

void TortoiseGitClient::Cleanup(const std::string& workingCopyPath)
{ RunCommand("cleanup", workingCopyPath); }

void TortoiseGitClient::Merge(const std::string& /*source*/, const std::string& targetWorkingCopyPath)
{
    // Git 的合并更多是分支与提交，不同于 SVN 的 fromurl。这里打开合并对话框。
    RunCommand("merge", targetWorkingCopyPath);
}

// ---------------- Factory ----------------
std::unique_ptr<IVersionControlClient> VersionControlFactory::Create(
    VcsType type,
    const std::string& tortoiseSvnPath,
    const std::string& tortoiseGitPath,
    const std::string& svnCliPath,
    const std::string& gitCliPath)
{
    switch (type)
    {
    case VcsType::TortoiseSVN: return std::make_unique<TortoiseSvnClient>(tortoiseSvnPath);
    case VcsType::TortoiseGIT: return std::make_unique<TortoiseGitClient>(tortoiseGitPath);
    case VcsType::SVN:         return std::make_unique<SvnCliClient>(svnCliPath);
    case VcsType::GIT:         return std::make_unique<GitCliClient>(gitCliPath);
    default:                   return std::make_unique<TortoiseSvnClient>(tortoiseSvnPath);
    }
}

// ---------------- SVN CLI ----------------
SvnCliClient::SvnCliClient(std::string svnExePath)
{
    m_exe = svnExePath.empty() ? "svn" : EnsureQuoted(svnExePath);
}

void SvnCliClient::RunConsole(const std::string& commandLine)
{
    // 简单起见，使用 cmd /C 同步执行
    Utility::StartProcess(m_exe + " " + commandLine);
}

void SvnCliClient::Update(const std::string& workingCopyPath)
{ RunConsole(std::string("update \"") + workingCopyPath + "\""); }

void SvnCliClient::Commit(const std::string& workingCopyPath)
{ RunConsole(std::string("commit \"") + workingCopyPath + "\" -m \"commit from GMTK\""); }

void SvnCliClient::Log(const std::string& workingCopyPath)
{ RunConsole(std::string("log \"") + workingCopyPath + "\" "); }

void SvnCliClient::Revert(const std::string& workingCopyPath)
{ RunConsole(std::string("revert -R \"") + workingCopyPath + "\""); }

void SvnCliClient::Cleanup(const std::string& workingCopyPath)
{ RunConsole(std::string("cleanup \"") + workingCopyPath + "\""); }

void SvnCliClient::Merge(const std::string& source, const std::string& targetWorkingCopyPath)
{ RunConsole(std::string("merge \"") + source + "\" \"" + targetWorkingCopyPath + "\""); }

// ---------------- Git CLI ----------------
GitCliClient::GitCliClient(std::string gitExePath)
{
    m_exe = gitExePath.empty() ? "git" : EnsureQuoted(gitExePath);
}

void GitCliClient::RunConsoleInRepo(const std::string& repoPath, const std::string& inlineCommands)
{
    // 在 repoPath 下执行 git 命令
    const std::string cmd = std::string("cmd.exe /C \"") + "cd /D " + EnsureQuoted(repoPath) + " && " + m_exe + " " + inlineCommands + "\"";
    Utility::StartProcess(cmd);
}

void GitCliClient::Update(const std::string& workingCopyPath)
{ RunConsoleInRepo(workingCopyPath, "pull"); }

void GitCliClient::Commit(const std::string& workingCopyPath)
{ RunConsoleInRepo(workingCopyPath, "commit -m \"commit from GMTK\""); }

void GitCliClient::Log(const std::string& workingCopyPath)
{ RunConsoleInRepo(workingCopyPath, "log --oneline -n 50"); }

void GitCliClient::Revert(const std::string& workingCopyPath)
{ RunConsoleInRepo(workingCopyPath, "restore ."); }

void GitCliClient::Cleanup(const std::string& workingCopyPath)
{ RunConsoleInRepo(workingCopyPath, "gc"); }

void GitCliClient::Merge(const std::string& /*source*/, const std::string& targetWorkingCopyPath)
{ RunConsoleInRepo(targetWorkingCopyPath, "merge"); }

